//    Copyright (C) Kherty.  All rights reserved.
using System;
using System.Collections.Generic;
using System.Diagnostics.Contracts;

namespace OpenLS.Spreadsheet.Collections
{
    class ClusteredDictionary<TValue>: IFrugalDictionary<TValue> where TValue: class
    {
        public ClusteredDictionary()
        {

        }
        int count;
        #region IFrugalDictionary<TValue> Members

        int IFrugalDictionary<TValue>.Count
        {
            get { return count ; }
        }

        public bool ContainsKey(int key)
        {
            TValue value;
            IFrugalDictionary<TValue> dic = this;
            return dic.TryGetValue(key, out value);
        }

        private const int ClusterSize = 128;
        bool IFrugalDictionary<TValue>.Remove(int key)
        {
            TValue[] cluster;
            int clustedId = key / ClusterSize;
            if (!clusters.TryGetValue(clustedId, out cluster))
            {
                return false;
            }
            int arrayIndex = key%ClusterSize;
            if (cluster[arrayIndex] != null)
            {
                cluster[arrayIndex] = null;
                count--;
                return true;
            }
            return false;
        }

        IEnumerator<int> IFrugalDictionary<TValue>.GetEnumerator()
        {
            foreach (int k in this.clusters.Keys)
            {
                TValue[] cluster = clusters[k];
                for (int i = 0; i < ClusterSize; i++)
                {
                    if (cluster[i] != null)
                        yield return k * ClusterSize + i;
                }
            }
        }

        bool IFrugalDictionary<TValue>.TryGetValue(int key, out TValue value)
        {
            int clusterId = key / ClusterSize;
            TValue [] cluster;
            if (!clusters.TryGetValue(clusterId, out cluster))
            {
                value = default(TValue);
                return false;
            }
            int arrayIndex = key%ClusterSize;
            value = cluster[arrayIndex];
            return value != null;
        }

        IFrugalDictionary<TValue> IFrugalDictionary<TValue>.TryAddValue(int key, TValue value)
        {
#if DEBUG
            Contract.Requires(!this.ContainsKey(key));
#endif
            int clustedId = key / ClusterSize;
            TValue [] cluster;
            if (!clusters.TryGetValue(clustedId, out cluster))
            {
                cluster = new TValue[ClusterSize];
                clusters.Add(clustedId, cluster);
            }
            cluster[key%ClusterSize] = value;
            count++;
            return null;
        }
        CachedDictionary<TValue[]> clusters = new CachedDictionary<TValue[]>();

        #endregion
    }
}
